﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Design;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using Storm;
using Storm.Docking;
using Storm.Docking.Controls;
using Storm.Docking.Controls.Float;
using Storm.Docking.Visual;
using Storm.Docking.Visual.Drawing;
using Storm.Docking.Visual.Glyphs;

namespace Storm.Docking.Visual.Drawing
{
	/// <summary>
	/// Class used for drawing all Controls in a DockPane.
	/// </summary>
	public class DockRenderer
	{
		#region Fields

		private DockColorTable colorTable = null;

		#endregion

		#region Properties

		/// <summary>
		/// Gets or sets the color table of the DockRenderer.
		/// </summary>
		public virtual DockColorTable DockColorTable
		{
			get { return colorTable; }
			set { colorTable = value; }
		}

		#endregion

		#region Methods

		#region Public

		#region DockCaption

		public virtual void CaptionDrawBar(DockCaption c, Graphics g)
		{
			Color startColor = DockColorTable.CaptionNormalColorStart;
			Color endColor = DockColorTable.CaptionNormalColorEnd;
			Color textColor = DockColorTable.CaptionNormalTextForeColor;

			if (c.Focused == true)
			{
				startColor = DockColorTable.CaptionFocusColorStart;
				endColor = DockColorTable.CaptionFocusColorEnd;
				textColor = DockColorTable.CaptionFocusTextForeColor;
			}

			LinearGradientBrush brush = new LinearGradientBrush
				(c.Bounds.Location, new Point(c.Bounds.
					Location.X, c.Bounds.Location.Y +
					c.Size.Height), startColor, endColor);

			float diameter = DockColorTable.CaptionRadius * 2.0F;
			SizeF sizeF = new SizeF(diameter, diameter);

			GraphicsPath path = new GraphicsPath();
			RectangleF arc = new RectangleF(new PointF
				(c.Location.X, c.Location.Y), sizeF);

			// We have created our arc Rectangle - start 
			// creating the GraphicsPath.

			// Top left arc.

			path.AddArc(arc, 180, 90);

			// Top right arc.

			arc.X = c.Bounds.Right - diameter;
			path.AddArc(arc, 270, 90);

			// Base rectangle.

			path.AddRectangle(new Rectangle(new Point((int)path.
				PathPoints[0].X, (int)path.PathPoints[0].Y),
				c.Size));

			// Finally close the path and draw it.

			path.CloseFigure();

			g.FillPath(brush, path);
			g.DrawPath(BrushStack.GetPen(DockColorTable
				.CaptionBorderColor), path);

			// We will then draw our text. We use Graphics
			// drawing for this instead of a Label because
			// Labels block MouseDown events.

			// First calculate the place that the text
			// should be placed - we want the text to
			// be placed in the left side of the 
			// DockCaption, so position it there.

			PointF textPoint = new PointF(c.Location.X + 1,
				c.Location.Y + (c.Size.Height / 2)
				- (c.Font.GetHeight() / 2));

            string text = c.CaptionText;
            float maxWidth = c.Width - c.CloseGlyph.Width -
                c.OptionsGlyph.Width - (g.MeasureString("...",
                c.Font).Width);

            // Start word wrapping.

            if (g.MeasureString(text, c.Font).Width > maxWidth)
            {
                // We found that our text is lengthy - shorten.

                char currentAddChar = text[0];
                string newText = "";

                foreach (char ch in text)
                {
                    currentAddChar = ch;
                    newText += currentAddChar;
                    if (g.MeasureString(newText, c.Font).Width >= maxWidth)
                    {
                        newText = newText.Substring(0, newText.Length - 1);
                        newText += "...";

                        break;
                    }
                }

                text = newText;
            }

			g.DrawString(text, c.Font, BrushStack.GetBrush
                (textColor), textPoint);
		}

		#endregion

		#region DockTab

		public virtual void TabPaintBackground(DockTab t, Graphics g)
		{
			t.ClientRectangle.Offset(t.Location);
			PaintEventArgs e = new PaintEventArgs(g, t.ClientRectangle);
			GraphicsState state = g.Save();
			g.SmoothingMode = SmoothingMode.AntiAlias;

			try
			{
				g.TranslateTransform((float)-t.Location.X,
					(float)-t.Location.Y);

				t.InvokePaintAll(t.Parent, e);
			}
			finally
			{
				g.Restore(state);
				t.ClientRectangle.Offset(-t.Location.X, -t.Location.Y);
			}
		}

		public virtual void TabDrawTab(DockTab t, Graphics g, TabPage tabPage, int index)
		{
			Rectangle recBounds = t.GetTabRect(index);
			RectangleF tabTextArea = (RectangleF)t.GetTabRect(index);
			RectangleF tabArea = tabTextArea;

			Color tabColorStart = DockColorTable.TabNormalBackColorStart;
			Color tabColorEnd = DockColorTable.TabNormalBackColorEnd;
			Color tabBorderColor = DockColorTable.TabNormalBorderColor;
			Color textColor = DockColorTable.TabNormalForeColor;

			bool selected = t.SelectedIndex == index;
			bool hovering = t.HoverIndex == index && selected == false;
			if (selected == true)
			{
				// Update the earlier specified Colors to match that
				// the tab is focused instead of normal.

				tabColorStart = DockColorTable.TabFocusBackColorStart;
				tabColorEnd = DockColorTable.TabFocusBackColorEnd;
				tabBorderColor = DockColorTable.TabFocusBorderColor;
				textColor = DockColorTable.TabFocusForeColor;
			}

			if (hovering == true)
			{
				// Update the earlier specified Colors to match that
				// the tab is hovered over instead of normal.

				tabColorStart = DockColorTable.TabHoverBackColorStart;
				tabColorEnd = DockColorTable.TabHoverBackColorEnd;
				tabBorderColor = DockColorTable.TabHoverBorderColor;
				textColor = DockColorTable.TabHoverForeColor;
			}

			// Now that our Colors has been setup, we will start 
			// drawing the tab.

			Rectangle rect = new Rectangle(new Point((int)tabArea.X,
				(int)tabArea.Y), new Size((int)tabArea.Size.Width - 1,
				(int)tabArea.Size.Height - 2));

			LinearGradientBrush brush = new LinearGradientBrush
				(rect, tabColorStart, tabColorEnd, 90f);

			g.FillRoundedRectangle(brush, rect, (int)DockColorTable.
				TabRadius, RectangleEdgeFilter.BottomLeft |
				RectangleEdgeFilter.BottomRight);

			g.DrawRoundedRectangle(BrushStack.GetPen(tabBorderColor),
				rect, (int)DockColorTable.TabRadius,
				RectangleEdgeFilter.BottomLeft | RectangleEdgeFilter.
				BottomRight);

			if (tabPage.ImageIndex >= 0 && t.ImageList != null &&
				t.ImageList.Images.Count > tabPage.ImageIndex &&
				t.ImageList.Images[tabPage.ImageIndex] != null)
			{
				int leftMargin = 2;
				int rightMargin = 0;

				Image image = t.ImageList.Images[tabPage.ImageIndex];
				Rectangle imageBounds = new Rectangle(recBounds.X +
					leftMargin, recBounds.Y + 1,
					image.Width, image.Height);

				float adjust = (float)(leftMargin + image.Width +
					rightMargin);

				imageBounds.Y += (recBounds.Height - image.Height) / 2;
				tabArea.X += adjust;
				tabArea.Width -= adjust;

				tabTextArea.X += adjust - 4;
				tabTextArea.Width -= adjust + 4;

				g.DrawImage(image, imageBounds);
			}
			
			Brush textBrush = BrushStack.GetBrush(textColor);

            string text = tabPage.Text;
            float maxWidth = tabTextArea.Width - (g.MeasureString("...",
                t.Font).Width);

            // Start word wrapping.

            if (g.MeasureString(text, t.Font).Width > maxWidth)
            {
                // We found that our text is lengthy - shorten.

                char currentAddChar = text[0];
                string newText = "";

                foreach (char ch in text)
                {
                    currentAddChar = ch;
                    newText += currentAddChar;
                    if (g.MeasureString(newText, t.Font).Width >= maxWidth)
                    {
                        newText = newText.Substring(0, newText.Length - 1);
                        newText += "...";

                        break;
                    }
                }

                text = newText;
            }

			g.DrawString(text, t.Font, textBrush,
				tabTextArea, t.StringFormat);
		}

		#endregion

		#region Glyph

		/// <summary>
		/// Draws the Glyph as if the cursor was hovering over it.
		/// </summary>
		/// <param name="g">Graphics to draw with.</param>
		public virtual void GlyphDrawHover(Glyph glyph, Graphics g)
		{
			Color penColor = DockColorTable.GlyphNormalBorderColor;
			Color fillColorStart = DockColorTable.GlyphNormalFillColorStart;
			Color fillColorEnd = DockColorTable.GlyphNormalFillColorEnd;
			int radius = 2;

			if (glyph.DockCaption.Focused == true)
			{
				penColor = DockColorTable.GlyphHoverBorderColor;
				fillColorStart = DockColorTable.GlyphHoverFillColorStart;
				fillColorEnd = DockColorTable.GlyphHoverFillColorEnd;
			}

			LinearGradientBrush brush = new LinearGradientBrush(glyph.GlyphRect,
				fillColorStart, fillColorEnd, LinearGradientMode.Vertical);

			g.SmoothingMode = SmoothingMode.HighQuality;
			g.FillRoundedRectangle(brush, glyph.GlyphRect, radius);
			Rectangle borderRect = glyph.GlyphRect;

			borderRect.Width--;
			borderRect.Height--;

			g.DrawRoundedRectangle(BrushStack.GetPen(penColor),
				borderRect, radius);
		}

		/// <summary>
		/// Draws the Glyph as if the mouse had clicked it.
		/// </summary>
		/// <param name="g">Graphics to draw with.</param>
		public virtual void GlyphDrawPressed(Glyph glyph, Graphics g)
		{
			Color penColor = DockColorTable.GlyphPressedBorderColor;
			Color fillColorStart = DockColorTable.GlyphPressedFillColorStart;
			Color fillColorEnd = DockColorTable.GlyphPressedFillColorEnd;
			int radius = 2;

			LinearGradientBrush brush = new LinearGradientBrush(glyph.GlyphRect,
				fillColorStart, fillColorEnd, LinearGradientMode.Vertical);

			g.SmoothingMode = SmoothingMode.HighQuality;
			g.FillRoundedRectangle(brush, glyph.GlyphRect, radius);
			Rectangle borderRect = glyph.GlyphRect;

			borderRect.Width--;
			borderRect.Height--;

			g.DrawRoundedRectangle(BrushStack.GetPen(penColor),
				borderRect, radius);
		}

		#endregion

        #region DockForm

        public virtual void FormDrawForm(DockForm f, Graphics g)
        {
            Rectangle rect1 = new Rectangle(Point.Empty, f.Size);
            Rectangle rect2 = new Rectangle(Point.Empty, new Size
                    (rect1.Width - 1, rect1.Height - 1));

            g.SmoothingMode = SmoothingMode.AntiAlias;
            g.FillRoundedRectangle(BrushStack.GetBrush(f.BackColor), rect2, 
				this.DockColorTable.FormRadius);

            g.DrawRoundedRectangle(BrushStack.GetPen(f.Renderer.
				DockColorTable.FormBorderColor), rect2, 
				this.DockColorTable.FormRadius);
        }

        #endregion

        #endregion

        #endregion

		/// <summary>
		/// Initializes a new instance of the <see cref="DockRenderer"/> class.
		/// </summary>
		public DockRenderer()
		{
			colorTable = new DockColorTable();
		}
	}
}
